// eslint使用细则:
// 让vscode自动修正你的代码
// 1. 下载ESLint插件 - 注意作者名字
//  对插件进行扩展配置(全局)
//  来到settings.json中, 把这两句话添加到对象里最后面
//  "eslint.run": "onType",
//  "editor.codeActionsOnSave": {
//   "source.fixAll.eslint": true
//  },
// 2. 确保脚手架里有node_modules, 而且要让脚手架文件夹作为vscode根目录
// 3. 打开一个js代码, 确保右下角的eslint是V状态(如果不是点击一下选择everyWhere)
// 效果保存自动格式化, 处理eslint红线

// 可能遇到的问题:
// 1. 一保存美化插件又给我缩进了
// (1): vscode设置中 找到 "Format On Save" 把前面的勾去掉
// (2): vscode设置中 找到 "tabsize" 把前面的勾都去掉
// (3): 美化插件都卸载了

// 2. 如果保存单引号又变成了双引号
// vetur插件和eslint插件冲突

// 👉👉项目：
// 一、设置好基础
// 1.新建Login/index.vue；
// 2.App里留好显示位<router-view>
// 3.路由引入样式style

// 二、顶部导航样式
// 1.新建vue.config.js，复制代码
// 2.styles/cover.less下，复制代码，对某一个组件样式覆盖
// 3.main.js里，引用'vant/lib/index.less'

// 三、组件库复制表单组件

// 四、请求接口
// 1.api/index.js写完
// 2.引入登录页面中的index.vue中
// 3.方法中继续写，这时是数组---提示验证码错误

// 五、给用户提示框
// 1.组件库里找
// 2.新建ui/Notify.js，导入导出
// 3.引入统一的通知方法
// 4.优化：避免用户多次点击，禁用

// 六、登录结果--保存token到vuex中
// 1.新建store/userModule，定义一个专门存储用户token值的变量(给了俩更新的方法)。导出。
// 2.定义完后，记得命名空间管理
// 3.store/index.js中注册
// 4.回到登录页面index.vue，存到vuex上(用辅助函数映射)；结构赋值，传到vuex里去

// 七、token值持久化
// 1.工具在store/storage.js浏览器本地存储的技术方案
// 2.userModule中导入和存值

// 八、实现layout布局和配置路由
// 1.新建views/Layout/index.vue
// 2.给路由添加前置守卫(不登录不允许进入)：
//   1.router/permission前置守卫
//   2.main.js中引入
// 3.登录成功后，设置js跳转到首页
//   this.$router.push('/')

// 九、首页-底部tabbar
// 1.组件库引入Tabbar TabbarItem
// 2.准备Layout下的二级路由嵌套-Home/User.vue

// 十、首页-头部静态标签
// 图片和模板

// 十一、频道列表
// 1.组件网引入注册组件
// 2.接口文档，动态数据搞定-api/index.js - 定义接口

// home页面分析：
// 整体：Home/index.vue
// 包含：头部；tabs频道条；组件页面列表Home/ArticleList；组件每个列表里又一样格式的内容Home/components/ArticleItem

// 23.6搜索历史--本地存储
// 输入框发生改变，先加入防抖函数里
// 监听改变，同步到本地

// 23.7搜索结果
// 一级路由，准备一个页面
// 配置路由，注意搜索结果接口传参:kw
// 点击事件跳转@click="$router.push(`/search/${str}`)"

// 23.8.0 搜索-请求数据铺设时
// 发现页面和ArticleItem里一样，所以复用组件。把该文件提到src下的Components文件夹
// 注册引入，遍历铺设

// 23.8.1组件复用-右下角x关闭
// x关闭是动态展示(v-if/v-show)
// 变量需要外面(ArticleItem)传值,声明变量
// SearchResult里动态显示，false

// 23.9加载更多数据
// 1.vant-list组件引用注册使用。
// 2.网页刚打开执行一次，让数据赋值到list上
// 3.判断。没有更多数据就关闭this.loading = false
// 4.页码++。第一页和第二页等等的数据合并到一起

// 24.0点击进去详情页
// 标签路由准备

// 24.1详情页请求数据渲染
// 请求接口
// 创建时获取文章id
// 循环遍历

// 24.2文章关注取关
// 添加点击事件，方法里布尔值区分
// 发现刷新后恢复，后台没改，需要接口
// 判断何时关注取关

// 24.4文章点赞取消 - 与上述相同
// 设置接口
// 点击事件
// 判断

// 25.0评论列表
// 新建组件
// 注意v-if和v-else，传参等

// 25.2.1加载更多offset
// 通过接口找到id，调用接口
// 首次不想拿值，第一页数据拿回来。但一会要传offset，所以在接口判断了offset(拼上下一页的参数)

// 25.2.2加载更多
// 网页一打开走一遍，10条；滚到底，再请求一次，又2条；第三次返回空，因为总共12条

// 25.2.3点亮小红心
// 点击事件分别
// 刚刚是文章id；这次评论是列表页，要点哪个，所以传参obj

// 25.5
// (网页打开时，v-show已经挂载到DOM上，v-if没有)
// 绑定点击事件，刚开始显示false。
// 获取焦点时，绑定焦点blur事件，记得这时DOM没渲染，拿不到$refs.area.focus()的值，所以用$nextTick

// 25.6-小徽标-评论数量
// 保存的当前评论数量，赋值
// 标签上动态获取totalCount且判断数量

// 25.6点击小徽标，到评论地方

// 25.6.0 --
// 问题：点击发布，先失去焦点了，点不了发布，所以点击事件无效
// 思考：只要让失去焦点的，隐藏标签改true的代码，慢点执行
// 解决：给失去焦点包个定时器(定时器在最后执行，是宏任务)

// 25.7.1 发布
// 点击事件
// 调用接口
// async,插入新的评论到头部

// userModule定义；用户页面映射mapMutations
// 封装组件，就是为了显示数据

// 26.2.0 个人中心-存储用户信息到vuex
// 1.store/userModule.js下, state里添加user变量: {}, 再定义mutations。
// 2.user/index.vue引用定义

// 26.2.1缓存信息-未出现时
// 先判断对象的名字是否有值:
// 有值时,本地缓存的有,就不用再请求了

// 26.3个人中心-退出功能
// 绑定点击事件
// 引入清空本地存储
// userModule清除
// 还可以加确认取消弹框

// 26.4个人中心--编辑
// 发现跳转新页面--新建页面，一级路由
// 用户页点击事件，跳转

// 26.5编辑--铺设
// 接口
// 注意铺设名字和生日时，用:value(vant组件有)

// 26.7.2 修改名称-调用接口-传值
// 正则判断符合要求--名字重复409--再次判断
// 一个新名字接收--新对象接收解构后的(不改变其他以前保存的)--新名字覆盖给obj.name。
// obj再传给setProfile身上

// 26.8 修改生日--反馈面板方法
// 点击修改生日，出现反馈面板(自定义)--时间选择器
// 点击时出现面板

// 26.8.1修改生日-调用接口
// 手动写年月日格式拼接(dayjs模块)
// 后台接口birthday，类型字符串
// 发给后台，成功后关闭弹窗；生日同步给profile里的变量，变量修改，页面用到的地方也都会更新
// 点击单元格让时间选择器出现-给页面上的默认生日(注意格式加上new Date才相等)

// 27.8前端集成socket.io实现聊天交互
// 下载引入；创建时连接另外一个服务器，得到一个连接对象
// 连接对象监测后台发送数据(拿回来的值是字符串)
// 发送时，还是要发送给后台emit

// 27.9自动滚动聊天框
// 发送成功后，DOM更新后：获取所有的div；获取最后一个，两边都要用scrollIntoView
// 解决：
// 方案1：window.scrollTo(0,坐标)
// 方案2：document.documentElement.scrollTop = 滚出去的高度
// 方案3：获取最后一个聊天的div，让它出现scrollIntoView

// 28.0 token续签
// 方案1: 前置跳转到登录页
// 只要发现 Token 过期，则强制用户跳转到登录页，并清空本地和 Store 中的关键数据！
// 方案2: 用户无感知
// 如果发现 Token 过期，则自动基于 refresh_token 无感知地请求一个新 Token 回来，在替换掉旧 Token 的同时，继续上次未完成的请求！用户体验好
// return阻止代码往下走
// axios2()再重新进行一次axios请求
// error.config - 原来的配置
